package com.tencent.wework.list

import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import java.util.concurrent.atomic.AtomicBoolean


/**
 * Created by huangwei on 2019/5/26.
 */
open class BaseRecyclerAdapter<C:BaseRecyclerCell<out Any>>:RecyclerView.Adapter<BaseViewHolder>() {
    protected var cells: MutableList<C> = ArrayList()
    protected var beginChange = AtomicBoolean(false)
    protected var recyclerView: RecyclerView? = null
    /**
     * 用于Diff判断
     */
    private var tempList: List<C> = ArrayList()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
        recyclerView = parent as RecyclerView
        val cell = getItem(getFirstPositionByType(viewType))
        return cell!!.createViewHolder(parent)
    }

    override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
        val cell = getItem(position)
        cell?.apply{
            adapter = this@BaseRecyclerAdapter
            recyclerView = this@BaseRecyclerAdapter.recyclerView
            bindViewHolder(holder, null)
        }
    }

    override fun onBindViewHolder(holder: BaseViewHolder, position: Int,payloads: MutableList<Any>) {
        val cell = getItem(position)
        cell?.apply{
            adapter = this@BaseRecyclerAdapter
            recyclerView = this@BaseRecyclerAdapter.recyclerView
            bindViewHolder(holder, payloads)
        }
    }
    override fun onViewRecycled(holder:BaseViewHolder) {
        super.onViewRecycled(holder)
        holder.onViewRecycled()
    }

    override fun getItemCount(): Int {
        return cells.size
    }

    override fun getItemViewType(position: Int): Int {
        val cell = getItem(position) ?: throw IllegalArgumentException("position:$position")
        return cell.getType()
    }

    private fun getFirstPositionByType(viewType: Int): Int {
        val size = itemCount
        for (i in 0 until size) {
            if (getItem(i)!!.getType() == viewType) {
                return i
            }
        }
        return -1
    }

    fun getItem(position: Int): C? {
        return if (position in 0 until itemCount) cells.get(position) else null
    }

    fun add(item: C?) {
        if (item == null) {
            return
        }
        val count = itemCount
        cells.add(item)
        if (!beginChange.get()) {
            notifyItemInserted(if (count == 0) 0 else count)
        }
    }

    fun add(index: Int, item: C?) {
        if (item == null) {
            return
        }
        cells.add(index, item)
        if (!beginChange.get()) {
            notifyItemInserted(index)
        }
    }

    fun addAll(array: Collection<C>) {
        addAll(itemCount, array)
    }

    fun addAll(position: Int, array: Collection<C>?) {
        if (array == null) {
            return
        }
        if (position < 0) {
            return
        }
        cells?.addAll(position, array)
        if (!beginChange.get()) {
            notifyItemRangeInserted(position, array.size)
        }
    }

    fun set(list: List<C>) {
        beginChange()
        cells.clear()
        cells.addAll(list)
        endChange(notifyChanged = true, detectMoves = false)
    }

    fun set(headerCount: Int, list: MutableList<C>) {
        if (headerCount > 0) {
            val headerList = ArrayList(cells.subList(0, headerCount))
            list.addAll(0, headerList)
        }
        beginChange()
        cells.clear()
        cells.addAll(list)
        endChange(true)
    }

    fun onDestroyView() {
        for (i in cells.indices) {
            val cell = cells[i]
            cell.onDestroyView()
        }
        recyclerView = null
    }

    fun remove(item: C) {
        val index = indexOf(item)
        remove(index)
    }

    fun remove(i: Int) {
        if (i < 0 || i >= itemCount) {
            return
        }
        cells.removeAt(i)
        if (!beginChange.get()) {
            notifyItemRemoved(i)
        }
    }

    /**
     * 移除元素，从start 到 end  ， start 和 end 都在范围内
     *
     * @param start
     * @param end
     */
    fun remove(start: Int, end: Int) {
        var start = start
        var end = end
        if (start > end) {
            return
        }
        start = if (start < 0) 0 else start
        val last = itemCount - 1
        end = if (end > last) last else end
        for (i in end downTo start) {
            cells.removeAt(i)
        }
        if (!beginChange.get()) {
            notifyItemRangeRemoved(start, end - start + 1)
        }
    }

    fun clear() {
        val start = 0
        val end = cells.size
        cells.clear()
        if (!beginChange.get()) {
            notifyItemRangeRemoved(start, end)
        }
    }

    fun indexOf(item: BaseRecyclerCell<out Any>): Int {
        return cells.indexOf(item)
    }


    fun beginChange() {
        tempList = ArrayList(cells)
        beginChange.set(true)
    }

    fun endChange(notifyChanged: Boolean, detectMoves: Boolean = true) {
        beginChange.set(false)
        if (!notifyChanged) {
            return
        }
        val diffResult = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
            override fun getOldListSize(): Int {
                return tempList.size
            }

            override fun getNewListSize(): Int {
                return cells.size
            }

            override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
                val oldCell = tempList[oldItemPosition]
                val newCell = cells[newItemPosition]
                return oldCell.areItemsTheSame(newCell)
            }

            /**走到这里表示两个cell的data是同一个，这里只是判断一下里面内容有没有局部更新，如果返回true，会继续调用下面
            的[getChangePayload]函数，获取局部更新的参数*/
            override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
                val oldCell = tempList[oldItemPosition]
                val newCell = cells[newItemPosition]
                val contentSame = oldCell.areContentsTheSame(newCell)
                //考虑到cell里可能保存了大量状态信息（例如选中态），所以如果检查到data没变，就延用老的cell，以保持状态信息
                cells[newItemPosition] = oldCell
                return contentSame
            }

            override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? {
                val oldCell = tempList[oldItemPosition]
                val newCell = cells[newItemPosition]
                return oldCell.getChangePayload(newCell)
            }
        }, detectMoves)
        diffResult.dispatchUpdatesTo(this)
    }
}